﻿using iS3.DAL.Attributes;
using iS3.DAL.Table;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace iS3.DAL
{
    public class DGBase
    {
        [
            PropertyKey(isAutoIncrement: true, isCanNull: false, isPrimaryKey: true),
            PropertyName(chsName: "编号"),
            PropertyDescription(description: "数据库主键"),
            PropertyDisplay(isCanIgnore: true, isCanOrder: true)
        ]
        public virtual long ID { get; set; }

        public  virtual DGEntityStruct LoadDesc()
        {
            Type typeInfo = this.GetType();
            DGEntityStruct result = new DGEntityStruct(typeInfo.Name);

            //table Name
            object[] tableNameAtts = iS3ReflectTool.GetAttributes(typeInfo, typeof(TableNameAttribute));
            if ((tableNameAtts == null) || (tableNameAtts.Length == 0))
            {
                result.TableName = result.EntityTypeName;   //若没有设置，则数据表表名与实体名称一致
            }
            else
            {
                result.TableName = (tableNameAtts[0] as TableNameAttribute).TableName;
            }

            //entity type
            object[] entityTypeAtts = iS3ReflectTool.GetAttributes(typeInfo, typeof(DGEntityTypeAttribute));
            if ((entityTypeAtts == null) || (entityTypeAtts.Length == 0))
            {

            }
            else
            {
                result.EntityDomain = (entityTypeAtts[0] as DGEntityTypeAttribute).Domain;
                result.EntityTypeName = (entityTypeAtts[0] as DGEntityTypeAttribute).DGName;

            }

            //property name
            List<PropertyInfo> piList = iS3ReflectTool.GetPropertyList(typeInfo);
            foreach (PropertyInfo pi in piList)
            {
                DGPropertyStruct dps = new DGPropertyStruct();
                dps.PropertyName = pi.Name;
                dps.SqlType = iS3DataType.GetSqlType(pi.PropertyType);

                object[] notAtts = iS3ReflectTool.GetAttributes(pi, typeof(NotMappedAttribute));

                if (!((notAtts == null) || (notAtts.Length == 0)))
                {
                    continue;
                }


                //key
                object[] keyAtts = iS3ReflectTool.GetAttributes(pi, typeof(PropertyKeyAttribute));
                if ((keyAtts == null) || (keyAtts.Length == 0))
                {
                    dps.IsPrimaryKey = false;
                    dps.IsAutoIncrement = false;
                    dps.IsCanNull = true;
                }
                else
                {
                    PropertyKeyAttribute keyAttr = (keyAtts[0] as PropertyKeyAttribute);
                    dps.IsPrimaryKey = keyAttr.IsPrimaryKey;
                    dps.IsAutoIncrement = keyAttr.IsAutoIncrement;
                    dps.IsCanNull = keyAttr.IsCanNull;
                }

                //propertyName
                object[] propertyAtts = iS3ReflectTool.GetAttributes(pi, typeof(PropertyNameAttribute));
                if ((propertyAtts == null) || (propertyAtts.Length == 0))
                {
                    dps.ChsName = null;
                }
                else
                {
                    PropertyNameAttribute propertyAtt = (propertyAtts[0] as PropertyNameAttribute);
                    dps.ChsName = propertyAtt.ChsName;
                }

                //Description
                object[] descriptionAtts = iS3ReflectTool.GetAttributes(pi, typeof(PropertyDescriptionAttribute));
                if ((descriptionAtts == null) || (descriptionAtts.Length == 0))
                {
                    dps.Description = null;
                }
                else
                {
                    PropertyDescriptionAttribute descriptionAtt = (descriptionAtts[0] as PropertyDescriptionAttribute);
                    dps.Description = descriptionAtt.Description;
                }

                //Dispaly
                object[] displayAtts = iS3ReflectTool.GetAttributes(pi, typeof(PropertyDisplayAttribute));
                if ((displayAtts == null) || (displayAtts.Length == 0))
                {
                    dps.IsCanIgnore = false;
                    dps.IsCanOrder = false;
                    dps.MaxLength = -1;
                }
                else
                {
                    PropertyDisplayAttribute displaynAtt = (displayAtts[0] as PropertyDisplayAttribute);
                    dps.IsCanIgnore = displaynAtt.IsCanIgnore;
                    dps.IsCanOrder = displaynAtt.IsCanOrder;
                    dps.MaxLength = displaynAtt.MaxLength;
                }

                //external
                object[] externalAtts = iS3ReflectTool.GetAttributes(pi, typeof(PropertyExternalAttribute));
                if ((externalAtts == null) || (externalAtts.Length == 0))
                {
                    dps.Unit = null;
                    dps.Example = null;
                }
                else
                {
                    PropertyExternalAttribute externalAttr = (externalAtts[0] as PropertyExternalAttribute);
                    dps.Unit = externalAttr.Unit;
                    dps.Example = externalAttr.Example;
                    dps.Target = externalAttr.Target;
                }


                result.Add(dps);
            }

            return result;
            return null;
        }
        public virtual DataTable TransformToDataTable(IEnumerable list,DGEntityStruct _struct=null)
        {
            Type typeInfo = this.GetType();
            DGEntityStruct des = _struct==null? DGEntityManager.GetInstance().GetStruct(typeInfo): _struct;
            List<PropertyInfo> piList = DGEntityManager.GetInstance().GetPropertys(typeInfo);

            DataTable dt = new DataTable();
            for (int i = 0; i < des.StructList.Count; i++)
            {
                dt.Columns.Add(des.StructList[i].PropertyName);
            }
            foreach (var data in list)
            {
                DataRow dr = dt.NewRow();
                foreach (var p in des.StructList)
                {
                    try
                    {
                        dr[p.PropertyName] = (data as DGBase).GetValue(p.PropertyName);
                    }
                    catch (Exception ex)
                    {
                        throw (ex);
                    }
                }
                dt.Rows.Add(dr);
            }
            return dt;
        }

        public virtual List<TEntity> TransformToEntity<TEntity>(DataTable dataTable,DGEntityStruct inputStruct=null) where TEntity : DGBase, new()
        {
            List<TEntity> res = new List<TEntity>();
            DGEntityStruct _struct = inputStruct==null? LoadDesc(): inputStruct;
            if (dataTable.Rows.Count > 0)
            {
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    TEntity _one = new TEntity();
                    foreach (var p in _struct.StructList)
                    {
                        try
                        {
                            string _outValue = dataTable.Rows[i][p.PropertyName].ToString();
                            _one.SetValue(p.PropertyName, _outValue);
                        }
                        catch (Exception ex)
                        {
                            _one.SetValue(p.PropertyName, null);
                        }

                    }
                    res.Add(_one);
                }
            }
            return res;
        }

        public virtual object GetValue(string propertyName)
        {
            try
            {
                PropertyInfo pi = DGEntityManager.GetInstance().GetProperty(this.GetType(), propertyName);

                return pi.GetValue(this);

            }
            catch (Exception ex)
            {
                return null;
            }

        }
        public virtual void SetValue(string propertyName,object data)
        {
            PropertyInfo pi = DGEntityManager.GetInstance().GetProperty(this.GetType(), propertyName);

           // pi.SetValue(this, Convert.ChangeType(data, pi.PropertyType));
           if (data == null)
            {
                pi.SetValue(this, null);
            }
            else
            {
                pi.SetValue(this, Convert.ChangeType(data, pi.PropertyType));
            }

        }
    }
}
